/**
 * @class $$.sql.reader.Querist
bar = {
	select : [news.id, news.title, newsclass.title, newsclass.id, user.id, user.title]
}
*/
$$.sql.Parser = function(){

	var data = this.data;
	if(!data) {
		data = this.data = {};
	}
	
	data.mainTable			= '';
	
	data.top				= {};
	data.top.value			= 0;
	data.top.sql			= '';
	
	data.field				= {};
	data.field.value		= [];
	data.field.sql			= '';
	
	data.subQuery			= {};
	data.subQuery.value		= [];
	data.subQuery.sql		= '';
	
	data.join				= {};
	data.join.value			= [];
	data.join.sql			= '';	
	
	data.filter				= {};
	data.filter.value		= [];
	data.filter.sql			= '';	
	
	data.orderBy			= {};
	data.orderBy.value		= [];
	data.orderBy.sql		= '';	
				
	data.noConflict			= {};
	data.noConflict.sql		= '';
	

	// for First
	this.setTop = function(num){
		this.data.top.value = num
		this.data.top.sql   = "TOP " + num;
		return this;
	}
	
	this.setField = function(field){
		this.data.field.value.push(field);
		this.data.field.sql += ' '+ field + ' ';
		return this;
	}
	
	// for fields
	this.setSubQuery = function(queristInstance, token){
		this.data.subQuery.value.push(queristInstance);
		this.data.subQuery.sql += ',(' + queristInstance.getQuerySql() + ') AS ' + token;
		return this;
	}
	
	this.setMainTable = function(mainTable){
		this.data.mainTable = mainTable;
		return this; 
	}
	
	/**
	 * for tables
	 * 生成下面的语句：
	 * USER] INNER JOIN (news INNER JOIN newsClass ON news.ClassID = newsClass.ID) ON USER.ID = news.SubmitterID;
	 * 有两个关系：
	 * student(s#,sname,d#),即学生这个关系有三个属性：学号，姓名，所在系别
	 * dep(d#,dname)，即院系有两个属性：系号、系名则s＃、d＃是主键，也是各自所在关系的唯一候选键，d＃是student的外键。
	 */
	this.setJoin = (function(){
		var  tpl = "({1} INNER JOIN {0} ON {3}.{4} = {1}.{2})";
		
		/**
		 * @param  {String}	mainTable
		 * @param  {Array}	tables
		 * @return {String}
		 */
		function makeJoin(mainTable, tables){
			var  
			 join
			,table 
			,inner		// 内面一层的join
			,out	= []; // Is this useful? @todo
	
			for(var i = 0, j = tables.length; i < j; i++){
				
				 table = tables[i]
				,inner = (i == 0) ? mainTable : out[i - 1]
				,join  = tpl.format(
					 inner
					,table.tableName
					,table.primaryKey
					,mainTable
					,table.foreignKey
				);
				
				out.push(join);
				
				// SELECT fields, noConflict
				if(table.noConflict){
					var noConflict = new String(' ');
					for(var q = 0, p = table.noConflict.length; q < p; q++){
						noConflict += ',' + table.noConflict[q] + ' ';
					}
					this.data.noConflict.sql = this.data.noConflict.sql + noConflict;
				}
			}
			return join;
		}
		return function(mainTable, tables){
			var thisJoin = this.data.join;
			
			// 保存value，就是保存參數
			thisJoin.value.push([ mainTable, tables]);
			// 不用join，沒有tables
			if(!tables){
				thisJoin.sql = mainTable;
				return thisJoin.sql;
			}
			
			// 如果有sql值存在，表示這是第二次調用join()，則mainTable為fn.sql
			if(thisJoin.sql && thisJoin.sql != ''){
				mainTable = thisJoin.sql;
			}
			
			thisJoin.sql = makeJoin.call(this, mainTable, tables); // 每次join操作都会破坏旧字符串
			return thisJoin.sql;
		}
	})()
	
	this.addJoin = function(join){
		var tmpJoin = this.data.tmpJoin;
		if(!tmpJoin){
			tmpJoin	= this.data.tmpJoin = [];
		}
		tmpJoin.push(join);
		return this;
	}
	
	// for where
	this.setFilter = function(fieldObj, operator, value){
		switch(fieldObj.type){
			case String:
				value = String(value);
				value = "'" + String.trim(value) + "'";
			break;
		}
		var filterSql = fieldObj.fullName + operator + value;
		 
		this.data.filter.value.push(filterSql);
		this.data.filter.sql += ' '+ filterSql + ' ';
		return this;
	}

	// for order
	this.orderBy = function(){
		return emptyStr;
		return this;
	}

	// for page
	this.limit = function(){
		return emptyStr;
		return this;
	}	
	
	this.getQuerySql = function(){
		var 
		 dummyStr	= ''
		,data		= this.data 
		,top 		// first
		,fields		// 字段
		,tables		// 关联表
		,filter 	// 查询条件
		,order;		// 排序

		 top	= data.top						.sql 	|| dummyStr
		,fields = (data.field.sql +  data.noConflict.sql)
		,fields = (
			 (data.field						.sql	|| dummyStr) 
			+(data.noConflict					.sql	|| dummyStr)
			+(data.subQuery						.sql	|| dummyStr)
		)												|| ' * '
		,tables = this.setJoin(data.mainTable, data.tmpJoin)
		,filter = data.filter.sql
		,filter = filter ? ' WHERE ' + filter 		 	 : dummyStr
		,order  = data.orderBy					.sql	|| dummyStr;
		
		fields += data.noConflict.sql; // a bug?
		
		return "SELECT " + top + fields + ' FROM ' + tables + filter + order;
	}
	
	// For write action
	
	var 
	 sqlTpl_Insert = 'INSERT INTO {0} ({1}) VALUES ({2})'
	,sqlTpl_Update = 'UPDATE {0} SET {1} WHERE id = {2}'
	,sqlTpl_Delete = 'DELETE FROM {0} WHERE id = {1}';
	
	/**
	 * @param  {Object} entityObj
	 * @param  {Action} action
	 * @return {String} SQL语句。
	 */
	function write(entityObj, action){
		var sql;
		
		switch(action){
			case $$.data.INITIALIZE: // 新建表格。
				var insertData = entityObj.eachFields(entity2insert, [ [], [] ]);
				
		        sql = sqlTpl_Insert.format(
			         entityObj.tableName
			        ,insertData[0].join(',')
			        ,json2sql(insertData[1].join(','))
		        ); 
			break;
			case $$.data.CREATE: 	// 执行SQL INSERT指令。
				var insertData = entityObj.eachFields(entity2insert, [ [], [] ]);
				
		        sql = sqlTpl_Insert.format(
			         entityObj.tableName
			        ,insertData[0].join(',')
			        ,json2sql(insertData[1].join(','))
		        ); 
			break;
			case $$.data.UPDATE: 	// 执行SQL UPDATE指令。
		        var
		         updateData = entityObj.eachFields(entity2update, [])
		        ,updateData = updateData.join(',');
	
		        sql = sqlTpl_Update.format(entityObj.tableName, updateData, entityObj.id); 
			break;
			case $$.data.DELETE: 	// 输入记录的id参数，删除记录。
				sql = sqlTpl_Delete.format(entityObj.tableName, entityObj.id);
			break;
			default:
				// warn
			break;
		}
		
		return sql;
	}
	
	/**
	 * @this {Array}
	 */
	function entity2insert(field){
		this[0].push(field.key);
		this[1].push(field.getSqlValue());
	}
	
	/**
	 * @this {Array}
	 */
	function entity2update(field){
		this.push(field.key + ' = ' + field.getSqlValue()); 
	}

	/**
	 * 送入一个JSON值，根据其类型返回符合SQL存储的字符串。
	 * @private
	 * @param 	{Any}	 v 	值
	 * @return 	{String} 	符合sQL存储的字符串。
	 */
	function json2sql(v){
	    switch(typeof(v)){
	        case 'boolean':
	        	break;
	        case 'string':
	            v = v.replace(/\'/g, "''").replace(/\r/g,"").replace(/(wh)(ere)/ig, "$1'+'$2");
			    v = "'"+ v +"'";
			break;
			case 'number':
				/*
				 * Access 双精度数字需要转换
				 * @dep
				if(false){
					v = " Format(" + v + ",'#0.0000') ";
				}*/
			break;
//				if (value && (typeof value.getFullYear == 'function')) {// 日期类型转换
//					value = "#" + value.format("Y-m-d h:i:s") + "#";
//				}
			case 'object':
	            if(v.toString() === new Date(v).toString()){ // 日期类型
	               v = (
	                $$.cfg.edk_dbType == 'mysql'
	                ? "'" + $$.Date.dateFormat(v, "yyyy-mm-dd HH:MM:ss") + "'"
	                : "#" + $$.Date.dateFormat(v, "yyyy-mm-dd HH:MM:ss") + "#"
	               );
	               break; 
	            }
			default : 
	            throw "unknow type!";
	    }
	    return v;
	}

	/**
	 * 这里一定要转换，因为COM日期类型到JS中很奇怪。
	 * 原理ADO Types -->JS Types
	 * 以字符出现date字眼为判断！
	 * @param 	{String}	key
	 * @param	{COM/COM+}	v
	 * @return	{Date}
	 */
	function getPrimitiveDate(key, v){
	    if(/date/i.test(key)){
	        v = new Date(v);
	    }
	    return v;
	}
	
//	this.getUpdateSql = write.delegate(this, $$.data.CREATE);
//	this.getInsertSql = write.delegate(this, $$.data.UPDATE);
//	this.getDelSql	  = write.delegate(this, $$.data.DELETE);
	
	/**
	 * 新建表格。
	 * @param 	{Object} 	entityObj
	 * @param 	{Boolean} 	isDropTable 	创建表格之前是否删除表格。
	 * @return 	{Boolean} 					True表示创建成功。
	 */
	this.getCreateTableSql = function(entityObj, isDropTable){
		var  
		 sql  = 'CREATE TABLE ' + tableName
		,meta = $$.Model.meta
		,fieldName
		,SQLType
		,arr  = [];
			
		for(fieldName in model){
			SQLType =  meta.getMeta.call(model[fieldName], meta.SQLType);
			switch(SQLType){
				case 'BOOLEAN':
					SQLType = ($$.cfg.edk_dbType == 'access') ? 'BIT' : SQLType;
				break;
				case 'CHAR':
					SQLType = 'CHAR({0})'.format(meta.getMeta.call(model[fieldName], meta.Length))
				break;
			}
			arr.push(fieldName + ' ' + SQLType + (fieldName == "ID" ? " NOT NULL PRIMARY KEY" : ""));
		}
		sql += '('+ arr.join('\n,') + ")";
		
		if(isDropTable){
			 	// Access不支持 IF EXIST……
				$$.sql.execute('DROP TABLE {0}'.format(tableName));
		}
		//进行数据库操作
		return sql;
	}
};